-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatically reload certificate and key PEM files #4372
Conversation
47394b3
to
e9bf920
Compare
} | ||
|
||
private void pollForFileChanges() { | ||
vertx.setPeriodic(FILE_POLLING_PERIOD_MSEC, id -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use the JDK file watcher instead?
FileSystems.getDefault().newWatchService()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing!
I had another try before this PR with a WatchService
and theads to run them master...Nordix:certificate-rotation.
My problem there is that I cannot find a reliable way to delete the watch filehandles and threads. The X509KeyManager
/ X509ExtendedKeyManager
interface have no close method and therefore they are not closed explicitly. I ran out of inotify filehandles when running test suite, since the key managers and the watches they hold were not garbage collected. I'd appreciate any ideas here!
Now currently, I've been experimenting with another approach that avoids periodic polling:
When key or certificate is requested from key manager, return cached versions unless time-to-live period (of e.g. 1 second or something else) has passed. If cache TTL has passed, check file modify timestamp. If the files have been modified then reload.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe another (secondary) reason to not use WatchService
is that they are sensitive on how the files are modified. In that previous link with my experiments, I added an example in comments how Kubernetes does the atomic swap of the files https://github.com/Nordix/vert.x/blob/db145f3ba4c6735a80fa005df1f30bdffd611b1a/src/main/java/io/vertx/core/net/impl/FileWatcher.java#L48-L85. One size does not fit all, so some configurability might need to be raised up all the way to all applications (through the frameworks that wrap Vert.x).
Some of the certificates in test resources had unintentionally expired. They could cause test errors if used in tests that expects valid certificates. * Reformatted ssl.txt file into a shell script ssl.sh which can be executed to regenerate certificates and keystores. * Updated all test certificates with 30 year expiration period (was 3 years). Signed-off-by: Tero Saarni <tero.saarni@est.tech>
* Implemented KeyStore that can reload PEM and PKCS#12 / JKS files wihtout server restart. * Use NewSunX509 KeyManager which selects server certificate based on SNI in TLS handshake among other selection criterias. Signed-off-by: Tero Saarni <tero.saarni@est.tech>
e9bf920
to
f74cc76
Compare
I've updated the PR content and the description. I would greatly appreciate feedback, and comments wether you agree on the approach and would be interested in incorporating hot-reload functionality into Vert.x. Note: Change stacks on top of #4388 PR branch in order to pass the tests. JSSE SNI server cert selection support requires valid certificate dates. |
I will have a look |
Friendly reminder, asking if you would have time for the review :) On slightly related note, in case it would be useful for the review: I've created a separate project and a design doc showing the ideas from this PR as a standalone project. |
ok, I would like to see if we can have it as something more decoupled from vertx core |
Thanks! Curious to hear if you'd have ideas about this! Since Vert.x is quite intensively manipulating KeyStores, it is already entangled with the code paths that would need to support hot-reload. Therefore it is bit difficult for me to figure out how decoupling could be achieved, That is, if #3780 is to be implemented in the first place. There is the "escape hatch" where application would not use Vert.X certificate loading support at all, but instead they would create and pass their own KeyManager, initialized with hot-reloading KeyStore. |
I've updated the PR description according to the discussion above. |
See #4568 |
This change adds support to hot-reload TLS certificate and key without requiring server restart. It makes it possible to automatically reload PEM files, PKCS#12 and JKS keystores, when they are configured as file paths.
Closes #3780
Why support for hot-reloading should be implemented in Vert.x core:
Currently the core provides API for thr user to configure KeyStore and certificate & key file paths. The files are loaded into memory and path information is discarded. The SSL context is associated with this in-memory KeyStore. Even if the underlying files would change, the static in-memory KeyStore, built by Vert.x core, remains static. It seems unavoidable that the code paths dealing with the files, construction of KeyStores, associating KeyStores with KeyManagers and finally with SSLContexts is impacted.
Alternative to the above could be not to use the the API that Vert.x provides for certificate or keystore path configuration, but instead user can provide their own custom KeyManager. This implies that #3780 would not be implemented in Vert.x but by each user should implement it by themselves.
The approach taken by this PR:
The change implements new key stores by extending JSSE
KeyStoreSpi
:PemFileKeyStoreSpi
loads and reloads PEM files, contructs single in-memory JSSE keystore from them and delegates operations to it.KeyStoreFileSpi
loads and reloads keystore files (PKCS#12 & JKS) and delegates operations to JSSE keystore.The files are reloaded when they are modified. Modification is observed by checking the file modification timestamp, but only when certificates and keys are used (when
KeyStoreSPI
methods are called) and the interval is capped bycacheTtl
, currently fixed to 1 check per second at most.Previously, handling of certificates was centered around crafting
KeyStore(s)
from values. The benefit was that handling of credentials configured "by-value" and "by-path" were all normalized into single "by-value" use case. To be able to reload, the path information must be kept around. The "reloading keystores" are constructed "by-path" directly inPemKeyCertOptions.java
andKeyStoreOptionsBase.java
.Previously selection of server certificate according to TLS SNI servername was implemented by custom-built logic by splitting each certificate in individual
KeyStore(s)
andKeyManager(s)
and picking one of those according to the SNI information from Netty, when handling new TLS connection. TheNewSunX509
version ofKeyManager
(from JDK 8) has support for selecting from multiple certificates in keystore according to SNI and other criterias, such as key type. This change proposes to change to JSSE's built-in SNI support. The side effect of this is that SNI support cannot be disabled anymoresetSni(false)
server option will not be effective: correct server certificate (according to SNI) will be returned from keystore when it previously could return incorrect one.For detailed information of the proposed implementation see this project and associated design document.
Signed-off-by: Tero Saarni tero.saarni@est.tech
Note: Change stacks on top of #4388 PR branch in order to pass the tests. JSSE SNI server cert selection support requires valid certificate dates.
TODOs